package com.geovis.emergency.spd.controller.system;


import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.geovis.common.auth.pojo.dto.AccessToken;
import com.geovis.common.auth.pojo.dto.LoginDTO;
import com.geovis.common.auth.props.AuthProperties;
import com.geovis.common.auth.util.AuthUtil;
import com.geovis.common.core.api.Result;
import com.geovis.common.core.controller.BaseController;
import com.geovis.common.mybatis.page.PageParam;
import com.geovis.common.mybatis.page.PageResult;
import com.geovis.emergency.spd.biz.filing.service.IFilingSystemUserService;
import com.geovis.emergency.spd.biz.pc.service.IPcDrillService;
import com.geovis.emergency.spd.biz.pc.service.IPcPlanService;
import com.geovis.emergency.spd.biz.system.service.ISystemDeptService;
import com.geovis.emergency.spd.biz.system.service.ISystemRoleService;
import com.geovis.emergency.spd.biz.system.service.ISystemUserService;
import com.geovis.emergency.spd.biz.zwdd.service.IZwddServcie;
import com.geovis.emergency.spd.entity.pc.pojo.enums.StatusEnum;
import com.geovis.emergency.spd.entity.system.entity.SystemDept;
import com.geovis.emergency.spd.entity.system.entity.SystemRole;
import com.geovis.emergency.spd.entity.system.entity.SystemUser;
import com.geovis.emergency.spd.entity.system.pojo.constant.SystemConstant;
import com.geovis.emergency.spd.entity.system.pojo.dto.*;
import com.geovis.oauth2.sdk.dto.ApiDeleteUser;
import com.geovis.oauth2.sdk.dto.ApiUserSaveOrUpdate;
import com.geovis.oauth2.sdk.dto.AuthUser;
import com.geovis.oauth2.sdk.service.IGeovisAuthService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.*;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户信息表 前端控制器
 * </p>
 *
 * @author 王响
 * @since 2020-07-15
 */
@RestController
@RequestMapping("/system/systemUser")
@RequiredArgsConstructor
@Api(value = "系统管理模块-用户信息相关接口", tags = "系统管理模块-用户信息相关接口")
@Slf4j
@Validated
public class SystemUserController extends BaseController<ISystemUserService> {

    private final PasswordEncoder passwordEncoder;

    private final IZwddServcie zwddServcie;

    private final RestTemplate lbRestTemplate;

    private final AuthProperties authProperties;

    private final IPcDrillService pcDrillService;

    private final IPcPlanService pcPlanService;
    @Autowired
    @Lazy
    private ISystemDeptService systemDeptService;

    private final IFilingSystemUserService filingSystemUserService;

    @Value("${geovis.deploy-path}")
    private String deployPath;

    @Value("${geovis.sso-index-url}")
    private String ssoIndexUrl;

    private final IGeovisAuthService geovisAuthService;

    private final ISystemRoleService roleService;

    @ApiOperation(value = "通过政务钉钉授权码登录", notes = "通过政务钉钉授权码登录")
    @PostMapping("/loginByZwddAuthCode/{authCode}")
    public Result<AccessToken> loginByZwddAuthCode(@PathVariable("authCode") String authCode) {
//        // 1、政务钉钉登录认证
//        EmployeeAccount employeeAccount = zwddServcie.authLogin(authCode);
//        // 2、系统颁发token
//        SystemUser systemUser = baseService.getById(employeeAccount.getEmployeeCode());
        SystemUser systemUser = baseService.getById(authCode);
        LoginDTO loginDTO = new LoginDTO();
        loginDTO.setUsername(systemUser.getUserName()).setPassword(authProperties.getDefaultPassword());
        JSONObject result = lbRestTemplate.postForObject(deployPath.concat(authProperties.getLoginUrl()), loginDTO, JSONObject.class);
        log.info(JSONUtil.toJsonStr(result));
        AccessToken data = JSONUtil.toBean(result.getJSONObject("data"), AccessToken.class);
        return Result.ok(data);
    }

    @ApiOperation(value = "集成单点登录", notes = "集成单点登录")
    @GetMapping("/loginByCode/{code}")
    public Result loginByCode(@PathVariable("code") String code) {
        com.geovis.oauth2.sdk.dto.Result<AuthUser> authUser = geovisAuthService.getUserByCode(code);
        if (authUser == null || authUser.getCode()!=200) {
            return Result.failed("调用认证中心获取用户失败:" + authUser.getMessage());
        }
        String url = deployPath + "/login";
        Map<String, String> reqBody = new LinkedHashMap<>();
        reqBody.put("username", authUser.getData().getUsername());
//        reqBody.put("username", "superadmin");
        //本系统的密码，固定是123456
        reqBody.put("password", "123456");
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders header = new HttpHeaders();
        header.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<Map<String, String>> entity = new HttpEntity<Map<String, String>>(reqBody, header);
        ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
        if (response.getStatusCode() != HttpStatus.OK) {
            log.error("登录系统响应错误！");
            log.error("body:{}", response.getBody());
            return null;
        }
        Map<String, Object> resMap = JSONUtil.parseObj(response.getBody());
        Integer resCode = (Integer) resMap.get("code");
        if (resCode != 200) {
            return Result.failed("预案系统登录失败");
        }
        String token = JSONUtil.parseObj(resMap.get("data")).get("accessToken").toString();
//        AccessToken data = JSONUtil.toBean(resMap.get("data").toString(), AccessToken.class);
        Map<String, String> data = new HashMap();
        data.put("tokenAuth", token);
        return Result.ok(data);
    }

    @ApiOperation(value = "获取当前登录用户信息", notes = "获取当前登录用户信息")
    @GetMapping("/getCurrUserInfo")
    public Result<LoginUserInfoDTO> getCurrUserInfo() {
        String currentUserId = AuthUtil.getCurrentUserId();
        if (ObjectUtil.isEmpty(currentUserId)) {
            Result.failed("未查到用户信息");
        }
        LoginUserInfoDTO loginUserInfoDTO = baseService.getByUserId(currentUserId);
        return Result.ok(loginUserInfoDTO);
    }

    @ApiOperation(value = "保存用户信息", notes = "保存用户信息")
    @PostMapping({"/save"})
    public Result<String> save(@Validated @RequestBody SystemUserSaveDTO saveDTO) {
        //
        if (SystemConstant.ADMIN_USER_NAME.equals(saveDTO.getUserName())) {
            return Result.failed("不能添加用户名为admin的用户");
        }
        //目前参考海政通逻辑，用户只存在叶子节点的部门，所以要校验用户选择的是否是叶子节点
        if (!systemDeptService.checkLeafNode(saveDTO.getDeptId())) {
            return Result.failed("选择的部门不是叶子节点，请重新选择");
        }
        baseService.save(saveDTO);
        SystemDept dept = systemDeptService.getById(saveDTO.getDeptId());
        SystemRole role = roleService.getById(saveDTO.getRoleIdList().get(0));
        //插入预案备案系统用户数据
        filingSystemUserService.saveOrUpdateUser(saveDTO, null, dept.getDeptName(), role.getName());
        //同步认证中心用户
        String password = StrUtil.isEmpty(saveDTO.getUserPassword()) ? SystemConstant.defaultPassword : saveDTO.getUserPassword();
        saveOrUpdateAuthCenterUser(saveDTO,password);
        return Result.ok();
    }

    /**
     * /同步认证中心用户
     */
    private void saveOrUpdateAuthCenterUser(SystemUserSaveDTO saveDTO,String password)
    {
        ApiUserSaveOrUpdate rzzxUser = new ApiUserSaveOrUpdate();
        BeanUtils.copyProperties(saveDTO, rzzxUser);
        rzzxUser.setPhoneNo(saveDTO.getPhone())
                .setUsername(saveDTO.getUserName());
        rzzxUser.setPassword(password);
        com.geovis.oauth2.sdk.dto.Result<?> result= geovisAuthService.userSaveOrUpdate(rzzxUser);
        if(result.getCode()!=200)
        {
            log.error("----同步用户中心失败-----name:"+saveDTO.getUserName()+"  error:"+result.getMessage());
        }
    }

    @ApiOperation(value = "修改用户信息", notes = "修改用户信息")
    @PostMapping({"/update"})
    public Result<String> update(@Validated @RequestBody SystemUserUpdateDTO updateDTO) {
        SystemUser user=baseService.getById(updateDTO.getId());
        //不是管理员的用户，不允许修改用户名为admin
        if(!SystemConstant.ADMIN_USER_NAME.equals(user.getUserName()) && SystemConstant.ADMIN_USER_NAME.equals(updateDTO.getUserName()))
        {
            return Result.failed("非管理员用户，不能设置用户名为admin");
        }
        //目前逻辑，用户只存在叶子节点的部门，所以要校验用户选择的是否是叶子节点
        if(!systemDeptService.checkLeafNode(updateDTO.getDeptId()))
        {
            return Result.failed("选择的部门不是叶子节点，请重新选择");
        }

        Set<String> ids=new HashSet<>();
        ids.add(user.getId());
        //如果设置停用，校验用户是否在预案和演练中
        String checkResult=null;
        if(StatusEnum.FALSE.getCode().equals(updateDTO.getDataStatus()))
        {
            String msg="，才能停用该用户";
            checkResult=checkUserInDrillOrPlan(ids,msg);
        }
        //如果修改了原部门，则要校验该用户是否在演练或预案中
        if(user.getDeptId()!=null && !updateDTO.getDeptId().equals(user.getDeptId()))
        {

            String msg="，才能更换该用户的部门";
            checkResult=checkUserInDrillOrPlan(ids,msg);
        }
        if(null!=checkResult)
        {
            return Result.failed(checkResult);
        }
        baseService.update(updateDTO);
        //更新预案备案系统用户数据
        SystemDept dept=systemDeptService.getById(updateDTO.getDeptId());
        SystemRole role=roleService.getById(updateDTO.getRoleIdList().get(0));
        SystemUserSaveDTO saveDTO=new SystemUserSaveDTO();
        BeanUtils.copyProperties(updateDTO,saveDTO);
        filingSystemUserService.saveOrUpdateUser(saveDTO,updateDTO.getUserName(),dept.getDeptName(),role.getName());
        //如果传了密码，则表示要重置密码
        String password = StrUtil.isEmpty(saveDTO.getUserPassword()) ? null : saveDTO.getUserPassword();
        saveOrUpdateAuthCenterUser(saveDTO,password);
        return Result.ok();
    }

    private String checkUserInDrillOrPlan(Set<String> ids,String msg)
    {
        String checkResult=null;
        //校验演练
        checkResult=pcDrillService.checkDrillExistUsers(ids);
        if(StringUtils.hasText(checkResult))
        {
            return checkResult+msg;
        }
        //校验预案
        checkResult=pcPlanService.checkPlanExistUsers(ids);
        if(StringUtils.hasText(checkResult))
        {
            return checkResult+msg;
        }
        return null;
    }

    @ApiOperation(value = "分页查询用户信息", notes = "分页查询用户信息")
    @PostMapping("/listPage")
    public Result<PageResult<SystemUserDTO>> listPage(@RequestBody @Validated PageParam<SystemUserQueryDTO> pageParam) {
        return Result.ok(baseService.listPage(pageParam));
    }

    @ApiOperation(value = "根据部门查询用户列表", notes = "查询用户列表")
    @GetMapping("/listByDeptId")
    public Result<List<SystemUser>> listByDeptId(String deptId) {
        return Result.ok(baseService.listByDeptIds(Arrays.asList(deptId)));
    }

    @ApiOperation(value = "批量删除数据", notes = "批量删除数据")
    @ApiImplicitParams({@ApiImplicitParam(name = "idList", value = "删除id的list", required = true, dataType = "java.util.Set", paramType = "body")})
    @PostMapping("/removeByIdList")
    public Result<String> removeByIdList(@NotNull(message = "删除的id集合不能为空") @RequestBody Set<String> idList) {

        //删除用户，需要校验2种情况，1.正在进行的演练，和尚未启动的演练里面已设置人员,2.方案里面已设置人员，
        String checkResult=null;
        String msg="，才能删除用户";
        //管理员不能删除
        if(baseService.isContainAdmin(idList))
        {
            return Result.failed("管理员，不能删除");
        }

        //校验演练
        checkResult=pcDrillService.checkDrillExistUsers(idList);
        if(StringUtils.hasText(checkResult))
        {
            return Result.failed(checkResult+msg);
        }
        //校验预案
        checkResult=pcPlanService.checkPlanExistUsers(idList);
        if(StringUtils.hasText(checkResult))
        {
            return Result.failed(checkResult+msg);
        }
        List<String> userNames=baseService.listByIds(idList).stream().map(SystemUser::getUserName).collect(Collectors.toList());
        baseService.removeByIdList(idList);

        //删除预案备案的用户
        filingSystemUserService.removeUsers(userNames);
        delAuthCenterUsers(userNames);
        return Result.ok();
    }

    /**
     * 删除认证中心用户
     */
    private void delAuthCenterUsers(List<String> userNames)
    {
        for(String userName:userNames)
        {
            ApiDeleteUser rzzxUser=new ApiDeleteUser();
            rzzxUser.setUsername(userName);
            geovisAuthService.deleteUser(rzzxUser);
        }
    }

    @ApiOperation(value = "修改用户密码", notes = "修改用户密码")
    @PostMapping("/changePassword")
    public Result<String> changePassword(@Validated @RequestBody SystemUserChangePasswordDTO changePasswordDTO) {
        SystemUser systemUser = baseService.getById(changePasswordDTO.getId());
        Assert.notNull(systemUser, "库里没有查询到此用户【{}】", changePasswordDTO.getId());
        if(!passwordEncoder.matches(changePasswordDTO.getOldPassword(), systemUser.getUserPassword()))
        {
            return Result.failed("旧密码不正确");
        }

        // 设置新密码
        systemUser.setUserPassword(passwordEncoder.encode(changePasswordDTO.getNewPassword()));
        baseService.updateById(systemUser);
        return Result.ok();
    }

    @ApiOperation(value = "分配角色", notes = "分配角色")
    @PostMapping("/assignRole")
    public Result<String> assignRole(@RequestBody SystemUserAssignRoleDTO assignRoleDTO) {
        baseService.assignRole(assignRoleDTO);
        return Result.ok();
    }





}
